﻿using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WCAD.Kean
{
    public class BoundaryExtraction
    {
        [CommandMethod("SB")]
        static public void SolidBoundaries()
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;
            // Set up our selection to only select 2D solids
            var pso = new PromptSelectionOptions();
            pso.MessageForAdding = "\nSelect 2D solid objects";
            var sf =new SelectionFilter(new TypedValue[]{new TypedValue((int)DxfCode.Start, "SOLID")});
            var psr = ed.GetSelection(pso, sf);
            if (psr.Status != PromptStatus.OK)
                return;
            int boundaries = 0;
            var tr = doc.TransactionManager.StartTransaction();
            using (tr)
            {
                foreach (SelectedObject so in psr.Value)
                {
                    var sol =tr.GetObject(so.ObjectId, OpenMode.ForRead) as Solid;
                    if (sol != null)
                    {
                        // We'll collect our points from the Solid
                        var pts = new Point3dCollection();
                        // Use a flipped indexing scheme: the 3rd & 4th vertices
                        // need to be flipped to go clockwise/anti-clockwise
                        foreach (var s in new short[] { 0, 1, 3, 2 })
                        {
                            var pt = sol.GetPointAt(s);
                            // If we have only 3 points then the 4th is a repeat
                            // of the 3rd (which in our case means the point in
                            // pts with an index of 1, as we flipped the indices)
                            if (s != 2 ||pt.DistanceTo(pts[2]) > Tolerance.Global.EqualPoint)
                            {
                                pts.Add(pt);
                            }
                        }
                        // We'll add our replacement boundary to the current
                        // space
                        var btr =(BlockTableRecord)tr.GetObject(db.CurrentSpaceId,OpenMode.ForWrite);
                        // We need a plane to define our polyline's 2D points
                        var plane = new Plane(pts[0], sol.Normal);
                        // Create the empty polyline in the plane of the solid
                        var pl = new Polyline(pts.Count);
                        pl.Normal = sol.Normal;
                        // Fill it with 2D points
                        for (int i = 0; i < pts.Count; i++)
                        {
                            // Add our converted 2D point to the vertex list
                            var pt2 = pts[i].Convert2d(plane);
                            pl.AddVertexAt(i, pt2, 0, 0, 0);
                        }
                        // Close the polyline
                        pl.Closed = true;
                        // Move it so that it overlaps the Solid
                        pl.TransformBy(Matrix3d.Displacement(pts[0].GetAsVector()));
                        // Add it to the current space and transaction
                        btr.AppendEntity(pl);
                        tr.AddNewlyCreatedDBObject(pl, true);
                        boundaries++;
                    }
                }
                tr.Commit();
            }
            ed.WriteMessage("\nCreated boundary polylines for {0} 2D solid objects.",boundaries);
        }
    }
}
